package binbase.web.gui

import core.MetaDataService
import binbase.web.core.BBBin
import core.BinBaseResultService
import binbase.web.core.BBDatabase

/**
 * synchronizes the voclib database with this application
 */
class SynchronizeJob {


    def grailsApplication

    def group = "binbase-${new Date()}"

    def synchronizeDatabaseService

    //only one job at a time...
    def concurrent = false

    /**
     * extracts the id for the given title
     * @param title
     * @return
     */
    private String getIdForTitle(String title) {
        try {
            //convert to id and accecpt it this way
            return new Integer(title).toString()
        }
        catch (NumberFormatException e) {

            File file = new File(grailsApplication.config.binbase.metaDataPath.toString())

            if (file.exists()) {
                for (File f in file.listFiles()) {
                    if (f.isDirectory() == false) {
                        if (f.name.endsWith(".xml")) {
                            def element = new XmlSlurper().parse(f)

                            def elementTitle = element.@title.text()

                            if (elementTitle == title) {
                                def id = element.@id.text().toString()
                                log.info "found id for ${title} and id was ${id}"

                                return id
                            }
                        }
                        else {
                            log.info "sorry was not an *.xml file: ${file}"
                        }
                    }
                }


            }
            else {
                log.info("sorry we were not able to find the data directory")
            }
        }

        return null
    }

    /**
     * does the actual synchronisation
     *
     * @return
     */
    def execute() {

        String database = grailsApplication.config.binbase.database.toString()

        boolean strict = grailsApplication.config.binbase.strict

        if (strict) {
            log.info "running in strict mode, experiments which have no metadata fieles will be ignored!"
        }
        //synchronizes the experimetns specified in the config files
        if (grailsApplication.config.binbase.syncExperiments != null && grailsApplication.config.binbase.syncExperiments instanceof Collection) {

            if (grailsApplication.config.binbase.syncExperiments.size() > 0) {
                log.info "synchronizing specific experiments: ${grailsApplication.config.binbase.syncExperiments}"

                grailsApplication.config.binbase.syncExperiments.each {def id ->

                    //convert to explicit string
                    id = id.toString()

                    //try to figure out if it's a title or an id
                    id = getIdForTitle(id)

                    boolean accept = true
                    if (strict) {

                        accept = fileExist(id)
                    }

                    if (accept) {
                        sync(id, database)
                    }
                    else {
                        log.info "sorry the file for ${id} was missing"
                    }
                }
            }
            else {
                log.info "no experiments defined in list, so synchroniztion is disabled"
            }

        }
        else if (!grailsApplication.config.binbase.syncExperiments) {
            log.info "synchronisation is disabled"
        }
        //if its empty we synchronize all files
        else {
            log.info "synchronizing all experiments"

            synchronizeDatabaseService.getExperimentsRequireSynchronisation(database).each { String id ->

                boolean accept = true

                //try to figure out if it's a title or an id
                id = getIdForTitle(id)

                if (strict) {

                    accept = fileExist(id)
                }

                if (accept) {
                    sync(id, database)
                }
                else {
                    log.info "sorry the file for ${id} was missing"
                }
            }
        }

    }

    /**
     * here we schedule the actual sub job to avoid session timeouts
     * @param id
     * @param database
     * @return
     */
    private def sync(id, database) {
        if (id == null) {
            log.info "id was null, no scheduling..."
        }
        else {
            log.info "scheduling: ${id} of database: ${database}"
            SynchronizeExperimentJob.triggerNow([experimentId: id, database: database])
        }
    }

    /**
     * checks of the given file exists
     * @param id
     * @return
     */
    boolean fileExist(String id) {

        if (grailsApplication.config.binbase.metaDataPath instanceof Collection) {
            grailsApplication.config.binbase.metaDataPath.each { String object ->
                File file = new File(object.toString())

                if (file.exists()) {
                    def f = new File(file, "${id}.xml")

                    if (f.exists()) {
                        return true
                    }
                }
            }

            return false
        }
        else {

            File file = new File(grailsApplication.config.binbase.metaDataPath.toString())

            if (file.exists()) {
                def f = new File(file, "${id}.xml")

                return f.exists()
            }

            return false

        }
    }
}
